package org.gdstash.character;

import org.gdstash.file.GDReader;
import org.gdstash.file.GDWriter;
import org.gdstash.item.GDItem;
import org.gdstash.util.FileVersionException;
import org.gdstash.util.GDMsgFormatter;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public class GDCharInventory {
    public static final int EQUIPPOS_HEAD = 0;
    public static final int EQUIPPOS_AMULET = 1;
    public static final int EQUIPPOS_CHEST = 2;
    public static final int EQUIPPOS_LEGS = 3;
    public static final int EQUIPPOS_FEET = 4;
    public static final int EQUIPPOS_HANDS = 5;
    public static final int EQUIPPOS_RING_LEFT = 6;
    public static final int EQUIPPOS_RING_RIGHT = 7;
    public static final int EQUIPPOS_BELT = 8;
    public static final int EQUIPPOS_SHOULDERS = 9;
    public static final int EQUIPPOS_MEDAL = 10;
    public static final int EQUIPPOS_ARTIFACT = 11;
    public static final int EQUIPPOS_MAINHAND = 0;
    public static final int EQUIPPOS_OFFHAND = 1;
    private static final int VERSION_4 = 4;
    private static final int VERSION_8 = 8;
    private static final int BLOCK = 3;
    private int version;
    private List<GDCharInventorySack> sacks;
    private GDCharEquippedContainer equipment;
    private int focused;
    private int selected;
    private byte flag;
    private GDChar gdc;

    public GDCharInventory(final GDChar gdc) {
        this.sacks = new LinkedList<GDCharInventorySack>();
        this.equipment = new GDCharEquippedContainer(gdc);
        this.gdc = gdc;
    }

    public GDCharInventorySack getInventory() {
        GDCharInventorySack sack = null;
        if (this.sacks != null) {
            try {
                sack = this.sacks.get(0);
            } catch (IndexOutOfBoundsException ex) {
                sack = null;
            }
        }
        return sack;
    }

    public List<GDCharInventorySack> getBags() {
        final List<GDCharInventorySack> list = new LinkedList<GDCharInventorySack>();
        if (this.sacks != null) {
            int i = 0;
            for (final GDCharInventorySack sack : this.sacks) {
                if (i > 0) {
                    list.add(sack);
                }
                ++i;
            }
        }
        return list;
    }

    public GDCharEquippedContainer getEquipment() {
        return this.equipment;
    }

    public List<GDItem> getItems() {
        final List<GDItem> list = new LinkedList<GDItem>();
        for (final GDCharInventorySack sack : this.sacks) {
            list.addAll(sack.getItemList());
        }
        list.addAll(this.equipment.getItemList());
        return list;
    }

    public boolean hasChanged() {
        boolean hasChanged = false;
        if (this.sacks != null) {
            for (final GDCharInventorySack sack : this.sacks) {
                hasChanged = (hasChanged || sack.hasChanged());
            }
        }
        hasChanged = (hasChanged || this.equipment.hasChanged());
        return hasChanged;
    }

    private boolean addBag() {
        boolean added = false;
        if (this.sacks != null) {
            int pos = 0;
            for (final GDCharInventorySack sack : this.sacks) {
                ++pos;
            }
            if (pos <= 5) {
                final GDCharInventorySack bag = new GDCharInventorySack(this.gdc, pos);
                this.sacks.add(bag);
                added = true;
            }
        }
        return added;
    }

    public void read() throws IOException {
        int val = 0;
        final GDReader.Block block = new GDReader.Block();
        val = GDReader.readBlockStart(block);
        if (val != 3) {
            throw new FileVersionException(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_UNSUPPORTED_VERSION"));
        }
        this.version = GDReader.readEncInt(true);
        if (this.version != 4 && this.version != 8) {
            throw new FileVersionException(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_UNSUPPORTED_VERSION"));
        }
        this.flag = GDReader.readEncByte();
        if (this.flag != 0) {
            final int numSacks = GDReader.readEncInt(true);
            this.focused = GDReader.readEncInt(true);
            this.selected = GDReader.readEncInt(true);
            this.sacks.clear();
            for (int i = 0; i < numSacks; ++i) {
                final GDCharInventorySack sack = new GDCharInventorySack(this.gdc, i);
                sack.read(this.version);
                this.sacks.add(sack);
            }
            this.equipment.read(this.version);
        }
        GDReader.readBlockEnd(block);
    }

    public void write() throws IOException {
        final GDReader.Block block = new GDReader.Block();
        GDWriter.writeBlockStart(block, 3);
        GDWriter.writeInt(this.version);
        GDWriter.writeByte(this.flag);
        if (this.flag != 0) {
            final int numSacks = this.sacks.size();
            GDWriter.writeInt(numSacks);
            GDWriter.writeInt(this.focused);
            GDWriter.writeInt(this.selected);
            for (final GDCharInventorySack sack : this.sacks) {
                sack.write(this.version);
            }
            this.equipment.write(this.version);
        }
        GDWriter.writeBlockEnd(block);
    }

    public int getByteSize() {
        int size = 0;
        size += 4;
        size += 4;
        size += 4;
        ++size;
        if (this.flag != 0) {
            size += 4;
            size += 4;
            size += 4;
            for (final GDCharInventorySack sack : this.sacks) {
                size += sack.getByteSize(this.version);
            }
            size += this.equipment.getByteSize(this.version);
        }
        size += 4;
        return size;
    }
}
